let tokenUtil = require('../token');
let pcService = require('./countryPhoneCodeService');
let http = require('../util/phttp');
let numUtil = require('../util/numUtil');
let redisConst = require('../const/redisConst');
let redis = require('../dao/redis');
let conf = require('../config/config');
let axios = require('axios');
let userDao = require('../dao/userDao');
let jiGuangSmsUtil = require('../util/jiGuangSmsUtil');
let RateLimiter = require('limiter').RateLimiter;
// 'second', 'minute', 'day', or a number of milliseconds
let limiter = new RateLimiter(10, 'second'); // 一秒钟限流10个
let registerLimiter = new RateLimiter(30, "second");
let safeBoxLimiter = new RateLimiter(30, "second");

const { BusiError, SysError } = require('../exception/exception');

class SmsService {
    constructor() {

    }

    /**
     *
     * @param {String} ip
     * @param {String} uid
     * @param {String} phone
     * @returns {Promise<void>}
     */
    async getModifySafeBoxValidCode(ip, uid, phone){
        let userInfo = await userDao.getUserByMobile(phone);
        if (!userInfo){
            throw new BusiError(500, "用户不存在");
        }

        if (userInfo.phone !== phone){
            throw new BusiError(500, "手机号有误");
        }

        if (!safeBoxLimiter.tryRemoveTokens(1)){
            throw new BusiError(500, "接口请求超出限制, 请稍后再试");
        }

        const limitKey = redisConst.SAFE_BOX_PWD_VALID_CODE_LIMIT + ":" + phone;
        let ok = await redis.lock(limitKey, 1, 60);
        if (!ok){
            throw new BusiError(500, "请求太频繁");
        }

        let areaCode = await pcService.getCountryCodeByIp(ip);
        if (!areaCode) areaCode = 86;
        let code = numUtil.random(1000, 9999);
        let checksum = tokenUtil.md5("+" + areaCode + phone + "_CHECK_" + code);
        let url = conf.conf['sms.ymg'] + "?mobile=%2B" + areaCode + phone + "&verifyCode=" + code + "&checksum=" + checksum;
        let ret = await axios.get(url);
        if (!ret) {
            console.logw("request verify code failed");
            throw new BusiError(500, "request verify code failed");
        }

        const cacheKey = redisConst.SAFE_BOX_PWD_VALID_CODE + ":" + phone;
        console.logw("手机号:", phone, "修改密码验证码:", code);
        await redis.set(cacheKey, code, 60 * 60);
    }

    async validSafeBoxPwdCode(phone, code){
        const cacheKey = redisConst.SAFE_BOX_PWD_VALID_CODE + ":" + phone;
        let cache = await redis.get(cacheKey);
        if (!cache){
            throw new BusiError(500, "验证码失效, 请重试");
        }

        if (String(cache) !== code){
            throw new BusiError(500, "验证码有误, 请仔细核对您的验证码");
        }

        await redis.del(cacheKey);
    }

    /**
     *
     * @param ip
     * @param phone
     * @param {String} countryCode
     * @returns {Promise<void>}
     */
    async getModifyPwdValidCode(ip, phone, countryCode){
        if (!limiter.tryRemoveTokens(1)){
            throw new BusiError(500, "接口请求超出限制, 请稍后再试");
        }

        const limitKey = redisConst.PWD_VALID_CODE_LIMIT + ":" + phone;
        let ok = await redis.lock(limitKey, 1, 60);
        if (!ok){
            throw new BusiError(500, "请求太频繁");
        }

        let areaCode = countryCode; //await pcService.getCountryCodeByIp(ip);
        if (!areaCode) areaCode = 86;
        let code = numUtil.random(1000, 9999);
        // code = "[金酷棋牌]您的修改密码验证码为: " + code;
        /*let checksum = tokenUtil.md5("+" + areaCode + phone + "_CHECK_" + code);
        let url = conf.conf['sms.ymg'] + "?mobile=%2B" + areaCode + phone + "&verifyCode=" + code + "&checksum=" + checksum;
        let ret = await axios.get(url);
        if (!ret) {
            console.logw("request verify code failed");
            throw new BusiError(500, "request verify code failed");
        }*/
        await jiGuangSmsUtil.sendPhoneCode(phone, code);

        const cacheKey = redisConst.PWD_VALID_CODE + ":" + phone;
        console.logw("手机号:", phone, "修改密码验证码:", code);
        await redis.set(cacheKey, code, 60 * 60);
    }

    /**
     *
     * @param phone
     * @param code
     * @returns {Promise<void>}
     */
    async validPwdCode(phone, code){
        const cacheKey = redisConst.PWD_VALID_CODE + ":" + phone;
        let cache = await redis.get(cacheKey);
        if (!cache){
            throw new BusiError(500, "验证码失效, 请重试");
        }

        if (String(cache) !== code){
            throw new BusiError(500, "验证码有误, 请仔细核对您的验证码");
        }

        await redis.del(cacheKey);
    }

    /**
     *
     * @param {String} phone
     * @param {String} ip
     * @returns {Promise<void>}
     */
    async getRegisterCode(ip, phone, countryCode){
        if (!registerLimiter.tryRemoveTokens(1)) {
            throw new BusiError(500, "接口请求超限, 请稍后再试");
        }

        let key = ip + "_" + phone;
        let getPhoneTick = await redis.getString(key);
        let time = (new Date().getTime() - Number(getPhoneTick)) / 1000;
        if (time < 50) {
            console.logw("获取手机验证码太频繁了");
            throw new BusiError(500, "请30秒后再试");
        }
        let code = numUtil.random(1000, 9999);
        console.logw("手机:", phone, "code:", code);
        // code = "[金酷棋牌]您的注册验证码为: " + code;

        /*let areaCode = countryCode; //await pcService.getCountryCodeByIp(ip);
        // if (!areaCode) areaCode = 86;
        let checksum = tokenUtil.md5(areaCode + phone + "_CHECK_" + code);
        let url = conf.conf['sms.ymg'] + "?mobile=" + areaCode + phone + "&verifyCode=" + code + "&checksum=" + checksum;
        let ret = await axios.get(url);
        if (!ret) {
            console.logw("request verify code failed");
            throw new BusiError(500, "请求验证码失败");
        }*/
        await jiGuangSmsUtil.sendPhoneCode(phone, code);

        await redis.setString(phone, code);
        await redis.setString(key, new Date().getTime());
        await redis.setExpire(key, 60 * 60 * 240); //10天过期
        await redis.setExpire(phone, 60 * 60 * 240); //10天过期

    }
}

let smsService = new SmsService();
module.exports = smsService;
